import * as THREE from 'three';
import { RoundedBoxGeometry } from 'three/examples/jsm/geometries/RoundedBoxGeometry.js';
import { MeshBVH, StaticGeometryGenerator } from 'three-mesh-bvh';
import { PointerLockControls } from 'three/examples/jsm/controls/PointerLockControls.js';

export default class PlayerController {
  constructor(scene, camera, renderer, domElement, collidableMeshes, options = {}) {
    this.scene = scene;
    this.camera = camera;
    this.renderer = renderer;
    this.domElement = domElement;
    this.collidableMeshes = collidableMeshes;
    
    // ========== 玩家物理参数配置 ==========
    this.options = {
      movementSpeed: 5.0,    // 基础移动速度 (m/s)
      runSpeed: 8.0,        // 奔跑速度 (m/s)
      jumpHeight: 5.0,      // 跳跃初速度 (m/s) 
      playerHeight: 1.8,    // 玩家模型高度 (m) - 标准成人身高约1.7-1.8m
      playerRadius: 0.5,    // 玩家碰撞体半径 (m) - 模拟人体宽度
      gravity: -30,         // 重力加速度 (m/s²) - 地球重力约-9.8，这里加强游戏性
      physicsSteps: 5,      // 物理更新迭代次数（提高稳定性）
      mouseSensitivity: 0.002, // 鼠标灵敏度
      ...options
    };

    // ========== 状态变量 ==========
    this.mode = 'none';     // 当前模式：'none' | 'first-person' | 'third-person'
    this.playerIsOnGround = false; // 是否在地面
    this.playerVelocity = new THREE.Vector3(); // 玩家速度向量
    
    // ========== 临时计算变量 ==========
    this.upVector = new THREE.Vector3(0, 1, 0); // 世界坐标系上向量
    this.tempVector = new THREE.Vector3();     // 临时向量1
    this.tempVector2 = new THREE.Vector3();    // 临时向量2
    this.tempBox = new THREE.Box3();           // 临时包围盒
    this.tempMat = new THREE.Matrix4();       // 临时矩阵
    this.tempSegment = new THREE.Line3();     // 临时线段（用于胶囊体碰撞检测）

    // ========== 输入状态 ==========
    this.fwdPressed = false; // W键 - 前进
    this.bkdPressed = false; // S键 - 后退
    this.lftPressed = false; // A键 - 左移
    this.rgtPressed = false; // D键 - 右移
    this.runPressed = false; // Shift键 - 奔跑

    // ========== 初始化 ==========
    this.initPlayer();          // 初始化玩家模型
    this.initEnvironment();     // 初始化碰撞环境
    this.initFirstPersonControls(); // 初始化第一人称控制器
    this.setupEventListeners(); // 设置事件监听
  }

  // ========== 初始化玩家模型 ==========
  initPlayer() {
    // 创建玩家碰撞体（使用圆角盒子模拟胶囊体）
    this.player = new THREE.Mesh(
      new RoundedBoxGeometry(
        this.options.playerRadius * 2,  // 宽度 (直径)
        this.options.playerHeight,      // 高度
        this.options.playerRadius * 2,  // 深度 (直径)
        10,    // 边缘细分
        0.5    // 圆角半径
      ),
      new THREE.MeshStandardMaterial({ visible: false }) // 不可见材质
    );
    
    // 调整几何体位置（使底部对齐原点）
    this.player.geometry.translate(0, -this.options.playerHeight / 2, 0);
    
    // 设置胶囊碰撞体参数（用于精确碰撞检测）
    this.player.capsuleInfo = {
      radius: this.options.playerRadius, // 碰撞半径
      segment: new THREE.Line3(          // 碰撞线段（从头顶到脚底）
        new THREE.Vector3(0, 0, 0),     // 线段起点（头顶位置）
        new THREE.Vector3(0, -this.options.playerHeight * 0.8, 0) // 线段终点（脚底上方20%）
      ),
    };

    this.scene.add(this.player);
  }

  // ========== 初始化碰撞环境 ==========
  initEnvironment() {
    if (this.collidableMeshes.length === 0) return;

    // 合并所有可碰撞网格的几何体
    const staticGenerator = new StaticGeometryGenerator(this.collidableMeshes);
    staticGenerator.attributes = ['position']; // 只需要位置属性
    const mergedGeometry = staticGenerator.generate();
    
    // 构建BVH（包围盒层次结构）加速碰撞检测
    mergedGeometry.boundsTree = new MeshBVH(mergedGeometry);
    
    // 创建不可见的碰撞器网格
    this.collider = new THREE.Mesh(mergedGeometry);
    this.collider.visible = false;
    this.scene.add(this.collider);
  }

  // ========== 初始化第一人称控制器 ==========
  initFirstPersonControls() {
    // 创建指针锁定控制器（鼠标控制视角）
    this.fpControls = new PointerLockControls(this.camera, this.domElement);
    this.scene.add(this.fpControls.getObject());
    
    // 初始化鼠标移动记录
    this.mouseMovement = { x: 0, y: 0 };
  }

  // ========== 设置事件监听 ==========
  setupEventListeners() {
    // 键盘按下事件
    this.keyDownHandler = (event) => {
      switch (event.code) {
        case 'KeyW': this.fwdPressed = true; break;
        case 'KeyS': this.bkdPressed = true; break;
        case 'KeyD': this.rgtPressed = true; break;
        case 'KeyA': this.lftPressed = true; break;
        case 'ShiftLeft': this.runPressed = true; break;
        case 'Space': // 空格键跳跃
          if (this.playerIsOnGround) {
            this.playerVelocity.y = this.options.jumpHeight; // 设置跳跃初速度
            this.playerIsOnGround = false; // 标记为空中状态
          }
          break;
      }
    };

    // 键盘释放事件
    this.keyUpHandler = (event) => {
      switch (event.code) {
        case 'KeyW': this.fwdPressed = false; break;
        case 'KeyS': this.bkdPressed = false; break;
        case 'KeyD': this.rgtPressed = false; break;
        case 'KeyA': this.lftPressed = false; break;
        case 'ShiftLeft': this.runPressed = false; break;
      }
    };

    // 鼠标移动事件（控制视角）
    this.mouseMoveHandler = (event) => {
      if (this.mode === 'first-person' && this.fpControls.isLocked) {
        this.mouseMovement.x = event.movementX;
        this.mouseMovement.y = event.movementY;
      }
    };

    // 点击事件（锁定指针）
    this.clickHandler = () => {
      if (this.mode === 'first-person' && !this.fpControls.isLocked) {
        this.fpControls.lock(); // 锁定鼠标指针
      }
    };

    // 添加事件监听
    document.addEventListener('keydown', this.keyDownHandler);
    document.addEventListener('keyup', this.keyUpHandler);
    document.addEventListener('mousemove', this.mouseMoveHandler);
    document.addEventListener('click', this.clickHandler);
  }

  // ========== 激活第一人称模式 ==========
  activateFirstPerson() {
    if (this.mode === 'first-person') return;
    
    this.deactivate(); // 先停用当前模式
    
    // 设置玩家初始位置（相机位置下方）
    this.player.position.copy(this.camera.position);
    this.player.position.y -= this.options.playerHeight * 0.8; // 眼睛高度
    
    // 重置玩家状态
    this.playerVelocity.set(0, 0, 0);
    this.playerIsOnGround = false;
    
    this.mode = 'first-person';
    this.fpControls.lock(); // 锁定鼠标指针
  }

  // ========== 停用控制器 ==========
  deactivate() {
    if (this.mode === 'none') return;
    
    if (this.mode === 'first-person') {
      this.fpControls.unlock(); // 解锁鼠标指针
    }
    
    this.mode = 'none';
  }

  // ========== 第一人称模式更新 ==========
  updateFirstPerson(delta) {
    if (!this.fpControls.isLocked) return;

    // ---- 1. 处理鼠标视角旋转 ----
    if (this.mouseMovement.x !== 0 || this.mouseMovement.y !== 0) {
        this.fpControls.moveRight(-this.mouseMovement.x * this.options.mouseSensitivity);
        this.fpControls.moveForward(-this.mouseMovement.y * this.options.mouseSensitivity);
        this.mouseMovement.x = 0;
        this.mouseMovement.y = 0;
    }

    // ---- 2. 物理模拟 ----
    // 应用重力
    if (this.playerIsOnGround) {
        this.playerVelocity.y = delta * this.options.gravity; // 地面时固定重力
    } else {
        this.playerVelocity.y += delta * this.options.gravity; // 空中时累积重力
    }

    // ---- 3. 移动控制 ----
    // 获取相机前方方向（忽略Y轴）
    const direction = new THREE.Vector3();
    this.camera.getWorldDirection(direction);
    direction.y = 0;
    direction.normalize();

    // 计算右方向（与前方垂直）
    const rightDirection = new THREE.Vector3();
    rightDirection.crossVectors(this.upVector, direction).normalize();

    // 计算当前移动速度
    const speed = this.runPressed ? this.options.runSpeed : this.options.movementSpeed;
    const moveDelta = speed * delta;

    // 处理键盘输入
    if (this.fwdPressed) {
        this.player.position.addScaledVector(direction, moveDelta); // 前进
    }
    if (this.bkdPressed) {
        this.player.position.addScaledVector(direction, -moveDelta); // 后退
    }
    if (this.lftPressed) {
        this.player.position.addScaledVector(rightDirection, moveDelta); // 左移
    }
    if (this.rgtPressed) {
        this.player.position.addScaledVector(rightDirection, -moveDelta); // 右移
    }

    // 应用速度
    this.player.position.addScaledVector(this.playerVelocity, delta);

    // ---- 4. 碰撞检测 ----
    this.updateCollision(delta);

    // ---- 5. 同步相机位置 ----
    // 第一人称相机位于玩家"眼睛"位置（高度为playerHeight的80%）
    this.camera.position.copy(this.player.position);
    this.camera.position.y += this.options.playerHeight * 0.8;
  }

  // ========== 碰撞检测 ==========
  updateCollision(delta) {
    if (!this.collider) return;

    // 1. 设置胶囊体线段（基于玩家当前位置）
    const capsuleInfo = this.player.capsuleInfo;
    this.tempSegment.copy(capsuleInfo.segment);
    this.tempSegment.start.add(this.player.position); // 线段起点
    this.tempSegment.end.add(this.player.position);   // 线段终点

    // 2. 计算胶囊体的包围盒（AABB）
    this.tempBox.makeEmpty();
    this.tempBox.expandByPoint(this.tempSegment.start);
    this.tempBox.expandByPoint(this.tempSegment.end);
    this.tempBox.min.addScalar(-capsuleInfo.radius); // 扩展半径
    this.tempBox.max.addScalar(capsuleInfo.radius);

    // 3. 转换到碰撞体局部空间
    this.tempMat.copy(this.collider.matrixWorld).invert();
    const localSegmentStart = this.tempSegment.start.clone().applyMatrix4(this.tempMat);
    const localSegmentEnd = this.tempSegment.end.clone().applyMatrix4(this.tempMat);
    const localSegment = new THREE.Line3(localSegmentStart, localSegmentEnd);

    // 4. 执行碰撞检测
    let hit = false;
    this.collider.geometry.boundsTree.shapecast({
      intersectsBounds: box => box.intersectsBox(this.tempBox), // 先检测包围盒
      intersectsTriangle: tri => { // 再检测三角形
        const triPoint = this.tempVector;
        const capsulePoint = this.tempVector2;
        
        // 计算胶囊体到三角形的最短距离
        const distance = tri.closestPointToSegment(localSegment, triPoint, capsulePoint);

        if (distance < capsuleInfo.radius) { // 发生碰撞
          hit = true;
          const depth = capsuleInfo.radius - distance; // 穿透深度
          const direction = capsulePoint.sub(triPoint).normalize(); // 碰撞方向
          
          // 调整玩家位置（推开玩家）
          const worldDirection = direction.clone().applyMatrix4(this.collider.matrixWorld);
          this.player.position.addScaledVector(worldDirection, depth);
        }
      }
    });

    // 5. 地面检测
    this.playerIsOnGround = hit;

    // 6. 掉落检测（防止玩家掉出世界）
    if (this.player.position.y < -15) {
      this.resetPosition();
    }
  }

  // ========== 重置玩家位置 ==========
  resetPosition() {
    this.player.position.set(0, 10, 0); // 重置到原点上方
    this.playerVelocity.set(0, 0, 0);   // 重置速度
    this.playerIsOnGround = false;     // 设置为空中状态
  }

  // ========== 主更新函数 ==========
  update(delta) {
    if (this.mode === 'none') return;
    
    // 限制delta时间（避免大时间步长导致物理不稳定）
    delta = Math.min(delta, 0.1);

    // 分步更新物理（提高稳定性）
    const physicsSteps = this.options.physicsSteps;
    for (let i = 0; i < physicsSteps; i++) {
      if (this.mode === 'first-person') {
        this.updateFirstPerson(delta / physicsSteps);
      }
    }
  }

  // ========== 资源清理 ==========
  dispose() {
    this.deactivate();
    
    // 移除事件监听
    document.removeEventListener('keydown', this.keyDownHandler);
    document.removeEventListener('keyup', this.keyUpHandler);
    document.removeEventListener('mousemove', this.mouseMoveHandler);
    document.removeEventListener('click', this.clickHandler);

    // 清理Three.js资源
    if (this.player) {
      this.scene.remove(this.player);
      this.player.geometry.dispose();
      this.player.material.dispose();
    }
    if (this.collider) {
      this.scene.remove(this.collider);
      this.collider.geometry.dispose();
    }
    if (this.fpControls) {
      this.scene.remove(this.fpControls.getObject());
      this.fpControls.dispose();
    }
  }
}